/*
 * ihex2bin.c: Read Intel HEX format, write binary data.
 *
 * By default reads from stdin and writes to stdout. The command-line
 * options `-i` and `-o` can be used to specify the input and output
 * file, respectively. Specifying an output file allows sparse writes.
 *
 * NOTE: Many Intel HEX files produced by compilers/etc have data
 * beginning at an address greater than zero, potentially causing very
 * unnecessarily large files to be created. The command-line option
 * `-a` can be used to specify the start address of the output file,
 * i.e., the value will be subtracted from the IHEX addresses (the
 * result must not be negative).
 *
 * Alternatively, the command-line option `-A` sets the address offset
 * to the first address that would be written (i.e., first byte of
 * data written will be at address 0).
 *
 * Copyright (c) 2013-2019 Kimmo Kulovesi, https://arkku.com
 * Provided with absolutely no warranty, use at your own risk only.
 * Distribute freely, mark modified copies as such.
 */
#include "stdafx.h"
#include "kk_ihex_read.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "SplitDemo.h"
#define AUTODETECT_ADDRESS (~0UL)

static FILE* outfile;
static unsigned long line_number = 1L;
static unsigned long file_position = 0L;
static unsigned long address_offset = 0UL;
static bool debug_enabled = 0;
#if 0
int main(int argc, char* argv[]) {
	struct ihex_state ihex;
	FILE* infile = stdin;
	ihex_count_t count;
	char buf[256];

	outfile = stdout;

	while (--argc) {
		char* arg = *(++argv);
		if (arg[0] == '-' && arg[1] && arg[2] == '\0') {
			switch (arg[1]) {
			case 'a':
				if (--argc == 0) {
					goto invalid_argument;
				}
				++argv;
				errno = 0;
				address_offset = strtoul(*argv, &arg, 0);
				if (errno || arg == *argv) {
					errno = errno ? errno : EINVAL;
					goto argument_error;
				}
				break;
			case 'A':
				address_offset = AUTODETECT_ADDRESS;
				break;
			case 'i':
				if (--argc == 0) {
					goto invalid_argument;
				}
				++argv;
				if (!(infile = fopen(*argv, "r"))) {
					goto argument_error;
				}
				break;
			case 'o':
				if (--argc == 0) {
					goto invalid_argument;
				}
				++argv;
				if (!(outfile = fopen(*argv, "wb"))) {
					goto argument_error;
				}
				break;
			case 'v':
				debug_enabled = 1;
				break;
			case 'h':
			case '?':
				arg = NULL;
				goto usage;
			default:
				goto invalid_argument;
			}
			continue;
		}
	invalid_argument:
		(void)fprintf(stderr, "Invalid argument: %s\n", arg);
	usage:
		(void)fprintf(stderr, "kk_ihex " KK_IHEX_VERSION
			" - Copyright (c) 2013-2015 Kimmo Kulovesi\n");
		(void)fprintf(stderr, "Usage: ihex2bin ([-a <address_offset>]|[-A])"
			" [-o <out.bin>] [-i <in.hex>] [-v]\n");
		return arg ? EXIT_FAILURE : EXIT_SUCCESS;
	argument_error:
		perror(*argv);
		return EXIT_FAILURE;
	}

	ihex_read_at_address(&ihex, (address_offset != AUTODETECT_ADDRESS) ?
		(ihex_address_t)address_offset :
	0);
	while (fgets(buf, sizeof(buf), infile)) {
		count = (ihex_count_t)strlen(buf);
		ihex_read_bytes(&ihex, buf, count);
		line_number += (count && buf[count - 1] == '\n');
	}
	ihex_end_read(&ihex);

	if (infile != stdin) {
		(void)fclose(infile);
	}

	return EXIT_SUCCESS;
}
#endif 
int nLinearAddr;
int ReadHexFile(char* srcFile, char* outFile, int nAddrOfset)
{
	struct ihex_state ihex;
	FILE* infile = stdin;
	ihex_count_t count = 0;
	line_number = 0;
	char buf[256];
	address_offset = AUTODETECT_ADDRESS;
	infile = fopen(srcFile, "r");
	outfile = fopen(outFile, "wb");
	nLinearAddr = nAddrOfset;
	ihex_read_at_address(&ihex, nAddrOfset);
	while (fgets(buf, sizeof(buf), infile))
	{
		//if (ihex.address >= nAddrOfset) && (ihex.type == IHEX_DATA_RECORD)
		{
			count = (ihex_count_t)strlen(buf);
			ihex_read_bytes(&ihex, buf, count);
			line_number += (count && buf[count - 1] == '\n');
		}

	}
	ihex_end_read(&ihex);
	(void)fclose(infile);

	return EXIT_SUCCESS;
}


TCHAR m_swzoffsetarray[500][20];
#include "SplitDemo.h"
int LoopHexFileLinearAddr(TCHAR* srcFile, CComboBox* pComboxHexOfset, int nBufSel,int &isHexType4, int &isHexType2)
{
	int i = 0;

	int cnt = 0;
	int loophexidx = 0;
	struct ihex_state ihex;
	TCHAR swzoffset[20], swzoffset1[20], swzAddrOut[20];
	FILE* infile = stdin;
	ihex_count_t count;
	char buf[256];
	address_offset = AUTODETECT_ADDRESS;
	memset(m_swzoffsetarray, 0, sizeof(m_swzoffsetarray));
	infile = _wfopen(srcFile, L"r");
	if (NULL == infile)
	{
		return -1;
	}
	outfile = NULL;
	pComboxHexOfset->ResetContent();
	ihex_read_at_address(&ihex, 0);
	while (fgets(buf, sizeof(buf), infile)) {
		count = (ihex_count_t)strlen(buf);
		ihex_read_bytes(&ihex, buf, count);
		line_number += (count && buf[count - 1] == '\n');
	
		if (ihex.type == IHEX_EXTENDED_LINEAR_ADDRESS_RECORD)
		{
		LOOP:
			isHexType4 = 1;
			wsprintf(swzoffset, L"%02x%02x", ihex.data[0], ihex.data[1]);
			fgets(buf, sizeof(buf), infile);
			count = (ihex_count_t)strlen(buf);
			ihex_read_bytes(&ihex, buf, count);

			line_number += (count && buf[count - 1] == '\n');
			if (ihex.type == IHEX_EXTENDED_LINEAR_ADDRESS_RECORD)
			{
				goto LOOP;
			}
			//R7F7010183AF
			if (pstuDevInfo[g_curDeviceSel].nLoadFileUserDef == 1)
			{
				ihex.address = 0;
			}
			wsprintf(swzoffset1, L"%04x", ihex.address);
			wcscat_s(swzoffset, swzoffset1);
			for (i = 0; i < 100; i++)
			{
				if (wcscmp(swzoffset, m_swzoffsetarray[i]) == 0)
					break;
			}
			if (i == 100)
			{
				//convertaddr(swzAddrOut, swzoffset, nBufSel);
				wcscpy(m_swzoffsetarray[cnt++], swzoffset);
				pComboxHexOfset->AddString(swzoffset);

			}

		}
		else if (ihex.type == IHEX_EXTENDED_SEGMENT_ADDRESS_RECORD)
		{
			int nsecaddr = ihex.data[0] * 256 + ihex.data[1];
			isHexType2 = 1;
			nsecaddr *= 16;
			//wsprintf(swzoffset, L"0x%02x%02x", ihex.data[0], ihex.data[1]);
			fgets(buf, sizeof(buf), infile);
			count = (ihex_count_t)strlen(buf);
			ihex_read_bytes(&ihex, buf, count);
			line_number += (count && buf[count - 1] == '\n');

			nsecaddr += ihex.address;
			//wsprintf(swzoffset1, L"%04x", ihex.address);
			//wcscat_s(swzoffset, swzoffset1);
			wsprintf(swzoffset, L"%08x", nsecaddr);
			for (i = 0; i < 100; i++)
			{
				if (wcscmp(swzoffset, m_swzoffsetarray[i]) == 0)
					break;
			}
			if (i == 100)
			{
				//convertaddr(swzAddrOut, swzoffset, nBufSel);
				wcscpy(m_swzoffsetarray[cnt++], swzoffset);
				pComboxHexOfset->AddString(swzoffset);

			}

		}
		else
		{
			if (loophexidx == 0)
			{
				wsprintf(swzoffset1, L"%x", ihex.address);
				pComboxHexOfset->AddString(swzoffset1);
			}
		}
		loophexidx++;


	}
	ihex_end_read(&ihex);
	(void)fclose(infile);


	if (pstuDevInfo[g_curDeviceSel].wBaseAddrEn & (1 << nBufSel))
	{
			
			CString strTmp;

			strTmp.Format(L"%08x", pstuDevInfo[g_curDeviceSel].nBufBaseAddr[nBufSel]);
			pComboxHexOfset->SetWindowTextW(strTmp);
		
		
	}
	else
	{
		if (pComboxHexOfset->GetCount())
		{
			pComboxHexOfset->SetCurSel(0);
		}
	}
	return EXIT_SUCCESS;
}
ihex_bool_t
ihex_data_read(struct ihex_state* ihex,
	ihex_record_type_t type,
	ihex_bool_t error) {
	if (error) {
		(void)fprintf(stderr, "Checksum error on line %lu\n", line_number);
		//exit(EXIT_FAILURE);
	}
	if ((error = (ihex->length < ihex->line_length))) {
		(void)fprintf(stderr, "Line length error on line %lu\n", line_number);
		// exit(EXIT_FAILURE);
	}
	if (!outfile) {
		return false;
	}
	if (type == IHEX_DATA_RECORD) {
		unsigned long address = (unsigned long)IHEX_LINEAR_ADDRESS(ihex);
		if (address < address_offset) {
			if (address_offset == AUTODETECT_ADDRESS) {
				// autodetect initial address
				address_offset = address;
				if (debug_enabled) {
					(void)fprintf(stderr, "Address offset: 0x%lx\n",
						address_offset);
				}
			}
			else {
				(void)fprintf(stderr, "Address underflow on line %lu\n",
					line_number);
				//   exit(EXIT_FAILURE);
			}
		}
		address -= address_offset;
		if (address != file_position) {
			if (debug_enabled) {
				(void)fprintf(stderr,
					"Seeking from 0x%lx to 0x%lx on line %lu\n",
					file_position, address, line_number);
			}

			/*   if (outfile == stdout || fseek(outfile, (long) address, SEEK_SET)) {
				   if (file_position < address) {
					   // "seek" forward in stdout by writing NUL bytes
					   do {
						   (void) fputc('\0', outfile);
					   } while (++file_position < address);
				   } else {
					   perror("fseek");
					   exit(EXIT_FAILURE);
				   }
			   }*/
			file_position = address;
		}
		if ((nLinearAddr >> 16) & (ihex->address >> 16))
		{
			if (!fwrite(ihex->data, ihex->length, 1, outfile)) {
				perror("fwrite");
				exit(EXIT_FAILURE);
			}
			file_position += ihex->length;
		}

	}
	else if ((type == IHEX_END_OF_FILE_RECORD)) {
		if (debug_enabled) {
			(void)fprintf(stderr, "%lu bytes written\n", file_position);
		}
		if (outfile != stdout) {
			(void)fclose(outfile);
		}
		outfile = NULL;
	}
	return true;
}
